package com.example.administrator.trains;

import android.app.Activity;
import android.content.Intent;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class Socket extends Activity  {
    CommunicationData data = new CommunicationData();
    public static Socket connector;
    public InputStream inputStream;
    public OutputStream outputStream;
    /*************底层通信协议******************/
    /*帧头*/
    public final static String Head = "5A";
    /*ACK ERROR 应答错误宏定义*/
    public final static String  ACK_OK = "00";

    /*************顶层通信协议******************/
    /*登陆相关部分*/
    /*命令类型*/
    public final static String LOGIN_CMD_TYPE = "A0";
    /*命令*/
    public final static String LOGIN_CMD = "01";
    public final static String REGISTER_CMD = "02";
    /*ACK*/
    public final static String REGISTER_SUCCESS_ACK = "00";
    public final static String REGISTER_USER_REPEAT_ERR_ACK = "01";
    public final static String LOGIN_SUCCESS_ACK = "02";
    public final static String LOGIN_NOT_MATCH_ERR_ACK = "03";
    public final static String ADMIN_LOGIN_SUCCESS_ACK = "04";
    /*车票相关部分*/
    public final static String TICKET_CMD_TYPE = "A1";
    /*命令*/
    public final static String FIND_TICKET = "03";
    public final static String BUY_TICKET = "04";
    public final static String FIND_ORDER = "05";
    public final static String RETURN_TICKET = "06";
    public final static String ALL_ORDER = "08";
    public final static String ADD_TICKET = "09";
    public final static String ALL_USER = "10";
    public final static String ADD_USER = "11";
    public final static String ADMIN_CHANGE_TICKET = "12";
    public final static String ADMIN_DELETE_TICKET = "13";
    public final static String ADMIN_CHANGE_USER = "14";
    public final static String ADMIN_DELETE_USER = "15";
    public final static String USER_FIND_TICKET = "17";
    /*ACK*/
    public final static String BUY_TICKET_SUCCESS_ACK = "04";
    public final static String RETURN_TICKET_SUCCESS_ACK = "05";
    public final static String NO_FIND_TICKET_ACK = "07";
    public final static String ADD_TICKET_SUCCESS_ACK = "08";
    public final static String ADD_TICKET_FALSE_ACK = "09";
    public final static String ADD_USER_SUCCESS_ACK = "10";
    public final static String ADD_USER_FALSE_ACK = "11";
    public final static String ADMIN_CHANGE_TICKET_SUCCESS_ACK = "12";
    public final static String ADMIN_CHANGE_TICKET_FALSE_ACK = "13";
    public final static String ADMIN_DELETE_TICKET_SUCCESS_ACK = "14";
    public final static String ADMIN_DELETE_TICKET_FALSE_ACK = "15";
    public final static String ADMIN_CHANGE_USER_SUCCESS_ACK = "16";
    public final static String ADMIN_CHANGE_USER_FALSE_ACK = "17";
    public final static String ADMIN_DELETE_USER_SUCCESS_ACK = "18";
    public final static String ADMIN_DELETE_USER_FALSE_ACK = "19";
    public final static String BUY_REPEATE_TICKET_ACK = "21";

    /*心跳相关部分*/
    public final static String HEART_CMD_TYPE = "A2";
    /*命令*/
    public final static String HEART_CMD = "18";

    private static Socket mSocketClientConnector;
    public static java.net.Socket mClient = null;
    private Thread mConnectThread, ConnectThread;

    /*ack相关部分*/
    /* 命令类型 */
    public final static String ACK_CMD_TYPE = "A2";
    /* 命令 */
    public final static String ACK_CMD = "00";

    public static byte[] hexStringToByteArray(String hexString) {
        int len = hexString.length();
        byte[] bytes = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            bytes[i / 2] = (byte)((Character.digit(hexString.charAt(i), 16) << 4) + Character.digit(hexString.charAt(i + 1), 16));
        }
        return  bytes;
    }

    /**
     * byte[]数组转换为16进制的字符串
     *
     * @param bytes 要转换的字节数组
     * @return 转换后的结果
     */
    public static String bytesToHexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(0xFF & bytes[i]);
            if (hex.length() == 1) {
                sb.append('0');
            }
            sb.append(hex);
        }
        return sb.toString();
    }

    public static Socket getInstance() {
        if (mSocketClientConnector == null)
            mSocketClientConnector = new Socket();
        return mSocketClientConnector;
    }

    public void createConnect(final String mSerIP, final int mSerPort) {
        if (mConnectThread == null) {
            mConnectThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        connect(mSerIP, mSerPort);
                        inputStream = mClient.getInputStream();
                        outputStream = mClient.getOutputStream();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
            mConnectThread.start();
        }
    }

    /**
     * 与服务端进行连接
     *
     * @throws IOException
     */
    public void connect(final String mSerIP, final int mSerPort) throws IOException {
        if (mClient == null) {
            mClient = new java.net.Socket(mSerIP, mSerPort);
        }
    }

    /**
     * 发送数据
     *
     * @param send_data 需要发送的内容
     */
    public void send(final byte[] send_data) throws IOException {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    if (send_data == null) {
                        return;
                    }
                    outputStream = mClient.getOutputStream();
                    if (outputStream != null) {
                        outputStream.write(send_data);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    public CommunicationData rec_data(final byte[] buffer) throws IOException {
        ConnectThread = new Thread(new Runnable()  {
            @Override
            public void run()  {
                SemaphoreUtils_recv.getInstance().tryAcquire();
                int recvCount = 0;
                int ret = 0;
                char len = 0;
                try {
                        while (true) {
                            ret = inputStream.read(buffer, recvCount, 1);
                            if (recvCount == 0) {
                                if (buffer[0] != 90) {
                                    break;
                                }
                            }
                            if (recvCount == 3) {
                                len = ((char)(((buffer[3]) & 0x00FF) + (((buffer[2]) & 0x00FF) << 8)));
                            }
                            if (ret != -1) {
                                recvCount += ret;
                                if (recvCount == len + 5) {
                                    analyze_data(buffer);
                                    break;
                                }
                                continue;
                            }
                        }

                } catch (IOException e) {
                    e.printStackTrace();
                }
                SemaphoreUtils_recv.getInstance().release();
            }
        });
        ConnectThread.start();
        try {
            ConnectThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return data;
    }

    public void recv_ack() throws IOException {
        ConnectThread = new Thread(new Runnable()  {
            @Override
            public void run()  {
                SemaphoreUtils_recv.getInstance().tryAcquire();
                try {
                        byte[] buffer = new byte[1];
                        while (inputStream.read(buffer) != -1) {
                            if (buffer[0] == hexStringToByteArray(REGISTER_SUCCESS_ACK)[0]) {
                                CommunicationData.ack = REGISTER_SUCCESS_ACK;
                                break;
                            }
                            if (buffer[0] == hexStringToByteArray(REGISTER_USER_REPEAT_ERR_ACK)[0]) {
                                CommunicationData.ack = REGISTER_USER_REPEAT_ERR_ACK;
                                break;
                            }
                            if (buffer[0] == hexStringToByteArray(LOGIN_SUCCESS_ACK)[0]) {
                                CommunicationData.ack = LOGIN_SUCCESS_ACK;
                                break;
                            }
                            if (buffer[0] == hexStringToByteArray(LOGIN_NOT_MATCH_ERR_ACK)[0]) {
                                CommunicationData.ack = LOGIN_NOT_MATCH_ERR_ACK;
                                break;
                            }
                            if (buffer[0] == hexStringToByteArray(BUY_TICKET_SUCCESS_ACK)[0]) {
                                CommunicationData.ack = BUY_TICKET_SUCCESS_ACK;
                                break;
                            }
                            if (buffer[0] == hexStringToByteArray(RETURN_TICKET_SUCCESS_ACK)[0]) {
                                CommunicationData.ack = RETURN_TICKET_SUCCESS_ACK;
                                break;
                            }
                            if (buffer[0] == hexStringToByteArray(NO_FIND_TICKET_ACK)[0]) {
                                CommunicationData.ack = NO_FIND_TICKET_ACK;
                                break;
                            }
                            if (buffer[0] == hexStringToByteArray(ADMIN_LOGIN_SUCCESS_ACK)[0]) {
                                CommunicationData.ack = ADMIN_LOGIN_SUCCESS_ACK;
                                break;
                            }
                            if (buffer[0] == hexStringToByteArray(ADD_TICKET_SUCCESS_ACK)[0]) {
                                CommunicationData.ack = ADD_TICKET_SUCCESS_ACK;
                                break;
                            }
                            if (buffer[0] == hexStringToByteArray(ADD_TICKET_FALSE_ACK)[0]) {
                                CommunicationData.ack = ADD_TICKET_FALSE_ACK;
                                break;
                            }
                            if (buffer[0] == hexStringToByteArray(ADD_USER_SUCCESS_ACK)[0]) {
                                CommunicationData.ack = ADD_USER_SUCCESS_ACK;
                                break;
                            }
                            if (buffer[0] == hexStringToByteArray(ADD_USER_FALSE_ACK)[0]) {
                                CommunicationData.ack = ADD_USER_FALSE_ACK;
                                break;
                            }
                            if (buffer[0] == hexStringToByteArray(ADMIN_CHANGE_TICKET_SUCCESS_ACK)[0]) {
                                CommunicationData.ack = ADMIN_CHANGE_TICKET_SUCCESS_ACK;
                                break;
                            }
                            if (buffer[0] == hexStringToByteArray(ADMIN_CHANGE_TICKET_FALSE_ACK)[0]) {
                                CommunicationData.ack = ADMIN_CHANGE_TICKET_FALSE_ACK;
                                break;
                            }
                            if (buffer[0] == hexStringToByteArray(ADMIN_DELETE_TICKET_SUCCESS_ACK)[0]) {
                                CommunicationData.ack = ADMIN_DELETE_TICKET_SUCCESS_ACK;
                                break;
                            }
                            if (buffer[0] == hexStringToByteArray(ADMIN_DELETE_TICKET_FALSE_ACK)[0]) {
                                CommunicationData.ack = ADMIN_DELETE_TICKET_FALSE_ACK;
                                break;
                            }
                            if (buffer[0] == hexStringToByteArray(ADMIN_CHANGE_USER_SUCCESS_ACK)[0]) {
                                CommunicationData.ack = ADMIN_CHANGE_USER_SUCCESS_ACK;
                                break;
                            }
                            if (buffer[0] == hexStringToByteArray(ADMIN_CHANGE_USER_FALSE_ACK)[0]) {
                                CommunicationData.ack = ADMIN_CHANGE_USER_FALSE_ACK;
                                break;
                            }
                            if (buffer[0] == hexStringToByteArray(ADMIN_DELETE_USER_SUCCESS_ACK)[0]) {
                                CommunicationData.ack = ADMIN_DELETE_USER_SUCCESS_ACK;
                                break;
                            }
                            if (buffer[0] == hexStringToByteArray(ADMIN_DELETE_USER_FALSE_ACK)[0]) {
                                CommunicationData.ack = ADMIN_DELETE_USER_FALSE_ACK;
                                break;
                            }
                            if (buffer[0] == hexStringToByteArray(BUY_REPEATE_TICKET_ACK)[0]) {
                                CommunicationData.ack = BUY_REPEATE_TICKET_ACK;
                                break;
                            }
                        }
                } catch (IOException e) {
                    e.printStackTrace();
                }
                SemaphoreUtils_recv.getInstance().release();
            }
        });
        ConnectThread.start();
        try {
            ConnectThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 断开连接
     *
     * @throws IOException
     */
    public void disconnect() throws IOException {
        if (mClient != null) {
            mClient.close();
            mClient = null;
        }
    }

    public CommunicationData analyze_data(byte[] bytes) {
        char length_tmp = 0;

        //判断帧头和获取有效数据长度
        if (hexStringToByteArray(Head)[0] == bytes[0]) {
            if (hexStringToByteArray(Head)[0] == bytes[1]) {
                length_tmp = ((char)(((bytes[3]) & 0x00FF) + (((bytes[2]) & 0x00FF) << 8)));
                byte variable_byte[] = new byte[length_tmp - 3];
                byte device_byte[] = new byte[length_tmp];
                byte[] ack = new byte[1];
                ack[0] = 0;
                //截取出有效数组byte_tmp
                System.arraycopy(bytes, 7, variable_byte, 0, length_tmp - 4);
                System.arraycopy(bytes, 4, device_byte, 0, length_tmp - 1);
                //判断校验位
                if (bytes[4 + length_tmp] == check_lrc(device_byte, length_tmp)) {
                    data.cmd = Integer.toHexString(0xFF & bytes[4]);
                    data.ack = Integer.toHexString(0xFF & bytes[5]);

                    data.device_data = new String(variable_byte);
                }
            }
        }
        return data;
    }

    //生成底层数据
    private byte[] build_device_data(String type, String cmd, String ack, String data){
        char length_tmp = 0;
        byte[] type_byte = hexStringToByteArray(type);
        byte[] cmd_byte = hexStringToByteArray(cmd);
        byte[] ack_byte = hexStringToByteArray(ack);
        byte[] lrc = new byte[1];
        byte[] byte_data = byteMerger(byteMerger(byteMerger(type_byte,
                cmd_byte),
                ack_byte),
                data.getBytes());
        byte[] length = new byte[2];

        length_tmp = (char)byte_data.length;

        //获得校验位
        lrc[0] = check_lrc(byte_data, length_tmp);

        //char转化成byte[]
        length[0] = (byte) ((length_tmp >> 8) & 0xFF);
        length[1] = (byte) (length_tmp & 0xFF);

        return byteMerger(byteMerger(length, byte_data), lrc);
    }

    //打包数据
    public byte[] package_data(String cmd_type, String cmd, String ack, String data) {
        return byteMerger(byteMerger(hexStringToByteArray(Head),
                hexStringToByteArray(Head)),
                build_device_data(cmd_type, cmd, ack, data));
    }

    //生成底层数据
    private byte[] build_heart_data(String type, String cmd){
        char length_tmp = 0;
        byte[] type_byte = hexStringToByteArray(type);
        byte[] cmd_byte = hexStringToByteArray(cmd);
        byte[] lrc = new byte[1];
        byte[] byte_data = byteMerger(type_byte, cmd_byte);
        byte[] length = new byte[2];

        length_tmp = (char)byte_data.length;

        //获得校验位
        lrc[0] = check_lrc(byte_data, length_tmp);

        //char转化成byte[]
        length[0] = (byte) ((length_tmp >> 8) & 0xFF);
        length[1] = (byte) (length_tmp & 0xFF);

        return byteMerger(byteMerger(length, byte_data), lrc);
    }

    public byte[] package_heart_data(String type, String cmd) {
        return byteMerger(byteMerger(hexStringToByteArray(Head),
                hexStringToByteArray(Head)),
                build_heart_data(type, cmd));
    }

    //生成校验位
    private byte check_lrc(byte[] data, int length) {
        int i;
        byte chlrc = 0;

        for (i = 0 ; i < length; i++) {
            chlrc ^= data[i];
        }

        return chlrc;
    }

    //java 合并两个byte数组
    public static byte[] byteMerger(byte[] bt1, byte[] bt2){
        byte[] bt3 = new byte[bt1.length + bt2.length];
        int i = 0;
        for (byte bt: bt1) {
            bt3[i] = bt;
            i++;
        }

        for (byte bt: bt2) {
            bt3[i] = bt;
            i++;
        }
        return bt3;
    }

    public void releaseSocket(){
        if (SocketService.task != null) {
            SocketService.task.cancel();
            SocketService.task = null;
        }
        if (SocketService.timer != null) {
            SocketService.timer.purge();
            SocketService.timer.cancel();
            SocketService.timer = null;
        }
        if (mSocketClientConnector != null) {
            mSocketClientConnector = null;
        }
        if (mConnectThread != null) {
            mConnectThread = null;
        }
        try {
            disconnect();
        } catch (IOException e) {
            e.printStackTrace();
        }

        connector = null;
        connector = getInstance();
        connector.createConnect("1.116.195.97", 8888);
    }
}
